---
id: user-purchasing-products
title: OpenTelemetry Store - User Purchasing Products
description: The OpenTelemetry Demo is an example application published by the OpenTelemtry CNCF project. This use case covers viewing recommended products before adding them to the shopping cart.
hide_table_of_contents: false
keywords:
  - tracetest
  - trace-based testing
  - observability
  - distributed tracing
  - testing
image: https://res.cloudinary.com/djwdcmwdz/image/upload/v1698686403/docs/Blog_Thumbnail_14_rsvkmo.jpg
---

In this use case, we want to validate the following story:

```
As a consumer, after landing at home page
I want to see the shop recommended products, add the first one to my cart and pay for it on checkout
So I can have it shipped to my home
```

Something interesting about this process is that it is a composition of many of the previous use cases, executed in sequence:
1. [Get Recommended Products](/live-examples/opentelemetry-store/use-cases/get-recommended-products)
2. [Add Item into Shopping Cart](/live-examples/opentelemetry-store/use-cases/add-item-into-shopping-cart)
3. [Check Shopping Cart Contents](/live-examples/opentelemetry-store/use-cases/check-shopping-cart-contents)
4. [Checkout](/live-examples/opentelemetry-store/use-cases/checkout)

So in this case, we need to trigger four tests in sequence to achieve test the entire scenario and make these tests share data.

## Building a Test Suite for This Scenario

Using Tracetest, we can do that by [creating a test](/web-ui/creating-tests) for each step and later grouping these tests as [Test Suites](/web-ui/creating-test-suites) that have an [variable set](/concepts/variable-sets).

We can do that by creating the tests and Test Suites through the Web UI or using the CLI. In this example, we will use the CLI to create a Variable Set and then create the Test Suite with all tests needed. The [assertions](/concepts/assertions) that we will check are the same for every single test.

### Mapping Environment Variables

The first thing that we need to think about is to map the variables that are needed in this process. At first glance, we can identify the vars to the API address and the user ID:
With these variables, we can create the following definition file as saving as `user-buying-products.env`:

```sh
OTEL_API_URL=http://otel-shop-demo-frontend:8080/api
USER_ID=2491f868-88f1-4345-8836-d5d8511a9f83
```

### Creating Tests

After creating the environment file, we will create a test for each step, starting with [Get Recommended Products](/live-examples/opentelemetry-store/use-cases/get-recommended-products), which will be saved as `get-recommended-products.yaml`:

```yaml
type: Test
spec:
  name: Get recommended products
  trigger:
    type: http
    httpRequest:
      url: ${var:OTEL_API_URL}/recommendations?productIds=&sessionId=${var:USER_ID}&currencyCode=
      method: GET
      headers:
      - key: Content-Type
        value: application/json
  specs:
  - selector: span[tracetest.span.type="rpc" name="grpc.hipstershop.ProductCatalogService/GetProduct" rpc.system="grpc" rpc.method="GetProduct" rpc.service="hipstershop.ProductCatalogService"]
    assertions: # It should have 4 products on this list.
    - attr:tracetest.selected_spans.count = 4
  - selector: span[tracetest.span.type="rpc" name="/hipstershop.FeatureFlagService/GetFlag" rpc.system="grpc" rpc.method="GetFlag" rpc.service="hipstershop.FeatureFlagService"]
    assertions: # The feature flagger should be called for one product.
    - attr:tracetest.selected_spans.count = 1
  outputs:
  - name: PRODUCT_ID
    selector: span[tracetest.span.type="general" name="Tracetest trigger"]
    value: attr:tracetest.response.body | json_path '$[0].id'
```

Note that we have one important changes here: we are now using environment variables on the definition, like `${var:OTEL_API_URL}` and `${var:USER_ID}` on the trigger section and an output to fetch the first `${var:PRODUCT_ID}` that the user chose. This new environment variable will be used in the next tests.

The next step is to define the [Add Item into Shopping Cart](/live-examples/opentelemetry-store/use-cases/add-item-into-shopping-cart) test, which will be saved as `add-product-into-shopping-cart.yaml`:

```yaml
type: Test
spec:
  name: Add product into shopping cart
  description: Add a selected product to user shopping cart
  trigger:
    type: http
    httpRequest:
      url: ${var:OTEL_API_URL}/cart
      method: POST
      headers:
      - key: Content-Type
        value: application/json
      body: '{"item":{"productId":"${var:PRODUCT_ID}","quantity":1},"userId":"${var:USER_ID}"}'
  specs:
  - selector: span[tracetest.span.type="http" name="hipstershop.CartService/AddItem"]
    # The correct ProductID was sent to the Product Catalog API.
    assertions:
    - attr:app.product.id = "${var:PRODUCT_ID}"
  - selector: span[tracetest.span.type="database" name="HMSET" db.system="redis" db.redis.database_index="0"]
    # The product persisted correctly on the shopping cart.
    assertions:
    - attr:tracetest.selected_spans.count >= 1
```

After that, we will [Check Shopping Cart Contents](/live-examples/opentelemetry-store/use-cases/check-shopping-cart-contents) (on `check-shopping-cart-contents.yaml`), simulating a user validating the products selected before finishing the purchase:

```yaml
type: Test
spec:
  name: Check shopping cart contents
  trigger:
    type: http
    httpRequest:
      url: ${var:OTEL_API_URL}/cart?sessionId=${var:USER_ID}&currencyCode=
      method: GET
      headers:
      - key: Content-Type
        value: application/json
  specs:
  - selector: span[tracetest.span.type="rpc" name="hipstershop.ProductCatalogService/GetProduct" rpc.system="grpc" rpc.method="GetProduct" rpc.service="hipstershop.ProductCatalogService"]
    # The product previously added exists in the cart.
    assertions:
    - attr:app.product.id = "${var:PRODUCT_ID}"
  - selector: span[tracetest.span.type="general" name="Tracetest trigger"]
    # The size of the shopping cart should be at least 1.
    assertions:
    - attr:tracetest.response.body | json_path '$.items.length' >= 1
```

And finally, we have the [Checkout](/live-examples/opentelemetry-store/use-cases/checkout) action (`checkout.yaml`), where the user inputs the billing and shipping info and finishes buying the item in the shopping cart:

```yaml
type: Test
spec:
  name: Checking out shopping cart
  description: Checking out shopping cart
  trigger:
    type: http
    httpRequest:
      url: ${var:OTEL_API_URL}/checkout
      method: POST
      headers:
      - key: Content-Type
        value: application/json
      body: '{"userId":"${var:USER_ID}","email":"someone@example.com","address":{"streetAddress":"1600 Amphitheatre Parkway","state":"CA","country":"United States","city":"Mountain View","zipCode":"94043"},"userCurrency":"USD","creditCard":{"creditCardCvv":672,"creditCardExpirationMonth":1,"creditCardExpirationYear":2030,"creditCardNumber":"4432-8015-6152-0454"}}'
  specs:
  - selector: span[tracetest.span.type="rpc" name="hipstershop.CheckoutService/PlaceOrder"
      rpc.system="grpc" rpc.method="PlaceOrder" rpc.service="hipstershop.CheckoutService"]
    assertions: 
    # An order was placed.
    - attr:app.user.id = "${var:USER_ID}"
    - attr:app.order.items.count = 1
  - selector: span[tracetest.span.type="rpc" name="hipstershop.PaymentService/Charge" rpc.system="grpc" rpc.method="Charge" rpc.service="hipstershop.PaymentService"]
    assertions: 
    # The user was charged.
    - attr:rpc.grpc.status_code  =  0
    - attr:tracetest.selected_spans.count >= 1
  - selector: span[tracetest.span.type="rpc" name="hipstershop.ShippingService/ShipOrder" rpc.system="grpc" rpc.method="ShipOrder" rpc.service="hipstershop.ShippingService"]
    assertions: 
    # The product was shipped.
    - attr:rpc.grpc.status_code = 0
    - attr:tracetest.selected_spans.count >= 1
  - selector: span[tracetest.span.type="rpc" name="hipstershop.CartService/EmptyCart"
      rpc.system="grpc" rpc.method="EmptyCart" rpc.service="hipstershop.CartService"]
    assertions: 
    # The shopping cart was emptied.
    - attr:rpc.grpc.status_code = 0
    - attr:tracetest.selected_spans.count >= 1
```

### Creating the Test Suite

Now we wrap these files and create a Test Suite that will run these tests in sequence and will fail if any of the tests fail. We will call it `testsuite.yaml`:

```yml
type: TestSuite
spec:
  name: User purchasing products
  description: Simulate a process of a user purchasing products on Astronomy store
  steps:
  - ./get-recommended-products.yaml
  - ./add-product-into-shopping-cart.yaml
  - ./check-shopping-cart-contents.yaml
  - ./checkout.yaml
```

By having the test, Test Suite and environment files in the same directory, we can call the CLI and execute this Test Suite:

```sh
tracetest run testsuite -f testsuite.yaml -e user-buying-products.env
```

The result should be an output like this:

```sh
✔ User purchasing products (http://localhost:11633/testsuite/kRDUir0VR/run/1)
        ✔ Get recommended products (http://localhost:11633/test/XxH8irA4R/run/1/test)
        ✔ Add product into shopping cart (http://localhost:11633/test/j_N8i9AVR/run/1/test)
        ✔ Check shopping cart contents (http://localhost:11633/test/Y2jim9AVg/run/1/test)
        ✔ Checking out shopping cart (http://localhost:11633/test/VPCim90Vg/run/1/test)
```
